package com.prs.crm.flow.impl;

import java.util.Collection;

import org.courser.Util;
import org.springframework.beans.factory.annotation.Autowired;

import com.prs.crm.context.Constrains;
import com.prs.crm.domain.flow.WorkFlowHandler;
import com.prs.crm.domain.flow.WorkFlowInstance;
import com.prs.crm.domain.flow.WorkFlowInstanceNode;
import com.prs.crm.domain.flow.WorkFlowProcess;
import com.prs.crm.domain.flow.WorkFlowProcessNode;
import com.prs.crm.domain.flow.WorkFlowProcessNodeDetail;
import com.prs.crm.domain.hr.Person;
import com.prs.crm.exception.InValidException;
import com.prs.crm.flow.FlowActionListener;
import com.prs.crm.flow.FlowJudger;
import com.prs.crm.flow.WorkFlowExecutor;
import com.prs.crm.service.flow.WorkFlowProcessService;

/**
 * 流程执行器
 * @author courser.tijichen
 *
 * @param <T>
 */
public   class WorkFlowExecutorImpl implements WorkFlowExecutor {
	
	private WorkFlowProcessService workflowProcessService;
	
	private FlowJudger flowJudger;
	
	public WorkFlowProcessService getWorkflowProcessService() {
		return workflowProcessService;
	}
	
	@Autowired
	public void setFlowJudger(FlowJudger flowJudger) {
		this.flowJudger = flowJudger;
	}

	public FlowJudger getFlowJudger() {
		return flowJudger;
	}

	@Autowired
	public void setWorkflowProcessService(
			WorkFlowProcessService workflowProcessService) {
		this.workflowProcessService = workflowProcessService;
	}





	@SuppressWarnings("unchecked")
	private Class getProcessClass()
	{
		return WorkFlowProcess.class;
	}
	
	public WorkFlowProcess initialize(WorkFlowInstance instance,Person person)
	{
		try
		{
			WorkFlowProcess process = (WorkFlowProcess)getProcessClass().newInstance();
			process.setInstance(instance);
			process.setStartTime(Util.nowFullTime());
			process.setStatus(Constrains.WORKFLOWPROCESS_STATE_INIT);//状态为初始化
			this.getWorkflowProcessService().save(process);
			for (WorkFlowInstanceNode node : instance.getNodes())
			{
				WorkFlowProcessNode processNode = new WorkFlowProcessNode();
				processNode.setFlowProcess(process);
				processNode.setInstanceNode(node);
				processNode.setHandler(new WorkFlowHandler());
				processNode.getHandler().setDept(node.getHandler().getDept());
				processNode.getHandler().setRole(node.getHandler().getRole());
				processNode.getHandler().setPrincipal(node.getHandler().getPrincipal());
				processNode.getHandler().addExecutors(node.getHandler().getExecutors());
				processNode.setStatus(Constrains.WORKFLOWPROCESS_STATE_INIT);
				this.getWorkflowProcessService().saveProcessNode(processNode);
				process.addNode(processNode);
			}
			return  process;
		}
		catch (Exception e)
		{
			e.printStackTrace();
			throw new InValidException(e.getMessage());
		}
	}
	
	
	
	private void beforeStart(WorkFlowProcess process)
	{
		if (process!=null)
		{
			if (!process.getStatus().equals(Constrains.WORKFLOWPROCESS_STATE_INIT))
			{
				process.setStatus(Constrains.WORKFLOWPROCESS_STATE_INIT);
				process.setResult(Constrains.WORKFLOWPROCESS_RESULT_NULL);
				this.getWorkflowProcessService().save(process);
				this.getWorkflowProcessService().updateProcessNode(process, 
									Constrains.WORKFLOWPROCESS_STATE_INIT, Constrains.WORKFLOWPROCESS_RESULT_NULL);
			}
		}
	}
	
	/**
	 * 开始一个流程
	 */
	public Collection<WorkFlowProcessNode> start(WorkFlowProcess process)
	{
		try
		{
			Collection<WorkFlowProcessNode> nextNodes = null;
			beforeStart(process);
			WorkFlowProcessNode startNode = null;
			Collection<WorkFlowProcessNode> nodes = this.getWorkflowProcessService().getNodeByNodeType(process, Constrains.WORKFLOW_STARTNODE);
			if (nodes.size()>0)
			{
				startNode = nodes.iterator().next();
			}
			if (startNode.getHandler()!=null)
			{
				startNode.setStatus(Constrains.WORKFLOWPROCESS_STATE_PROCESS);
			}
			else
			{
				startNode.setResult(Constrains.WORKFLOWPROCESS_RESULT_PASS);//获取开始节点，并执行
				startNode.setStatus(Constrains.WORKFLOWPROCESS_STATE_END);
				this.getWorkflowProcessService().saveProcessNode(startNode);
				nextNodes = this.getWorkflowProcessService()
													.getNextProcessNodes(startNode);
				for (WorkFlowProcessNode node : nextNodes)
				{
					node.setStatus(Constrains.WORKFLOWPROCESS_STATE_PROCESS);
					this.getWorkflowProcessService().saveProcessNode(node);
				}
			}

			process.setStatus(Constrains.WORKFLOWPROCESS_STATE_PROCESS);
			process.setStartTime(Util.nowFullTime());
			this.getWorkflowProcessService().save(process);
			return nextNodes;
		
		}
		catch (Exception e)
		{
			e.printStackTrace();
			throw new InValidException(e.getMessage());
		}
	}
	
	/**
	 * 流程执行
	 * 忽略分支和汇聚结点
	 * @param node
	 * @param detail
	 */
	public Collection<WorkFlowProcessNode> execute(WorkFlowProcessNode node,WorkFlowProcessNodeDetail detail, FlowActionListener<?> listener)
	{
		detail.setHandleTime(Util.nowFullTime());
		node.setResult(detail.getResult());
		node.addDetail(detail);
		node.setStatus(this.getFlowJudger().judge(detail));
		node.setModifyTime(Util.nowFullTime());
		this.getWorkflowProcessService().saveProcessNode(node);
		//System.out.println(node.getFlowProcess()+"  workFlowExecutorImpl  execute");
		if (node.getStatus().equals(Constrains.WORKFLOWPROCESS_STATE_END))
		{
			//node.setStatus(Constrains.WORKFLOWPROCESS_STATE_END);
			this.getWorkflowProcessService().saveProcessNode(node);
			if (detail.getResult()==Constrains.WORKFLOWPROCESS_RESULT_PASS)
			{
				Collection<WorkFlowProcessNode> nextNodes = this.getWorkflowProcessService()
				.getNextProcessNodes(node);
				if (nextNodes!=null && nextNodes.size()>0)
				{
					 for (WorkFlowProcessNode nextNode : nextNodes)
					 {//System.out.println("1");
						 if (nextNode.getInstanceNode().getFlownode().getType() == Constrains.WORKFLOW_ENDNODE
								 && nextNode.getHandler()==null)
						 {
							 nextNode.setResult(Constrains.WORKFLOWPROCESS_RESULT_PASS);
							 nextNode.setStatus(Constrains.WORKFLOWPROCESS_STATE_END);
							 endProcess(node.getFlowProcess(),Constrains.WORKFLOWPROCESS_RESULT_PASS,listener);//结束整个流程执行
							 break;
						 }
						 nextNode.setStatus(Constrains.WORKFLOWPROCESS_STATE_PROCESS);
					 }
					 return nextNodes;
				}
				else
				{
					endProcess(node.getFlowProcess(),Constrains.WORKFLOWPROCESS_RESULT_PASS,listener);
					return null;
				}
				
			}
			else
			{
				endProcess(node.getFlowProcess(),Constrains.WORKFLOWPROCESS_RESULT_NOTPASS,listener);
				return null;
			}
		}
		else
		{
			return null;
		}
	}
	
	private void endProcess(WorkFlowProcess process,Integer result, FlowActionListener<?> listener)
	{
		process.setStatus(Constrains.WORKFLOWPROCESS_STATE_END);
		process.setEndTime(Util.nowFullTime());
		process.setResult(result);
		for (WorkFlowProcessNode node : process.getProcessNodes())
		{
			/**
			 * 流程结束时，对未执行的节点，设置过期
			 */
			if (node.getStatus() == Constrains.WORKFLOWPROCESS_STATE_PROCESS)
			{
				node.setStatus(Constrains.WORKFLOWPROCESS_STATE_OVERDUE);
			}
		}
		this.getWorkflowProcessService().save(process);
		processEndEvent(process,listener);
	}
	
	private void processEndEvent(WorkFlowProcess process, FlowActionListener<?> listener)
	{
		if (listener!=null)
		{
			listener.onProcessEnd(process);
		}
	}
	
}
